/**
 * @FileName: DemoController.java
 * @Package: top.swimmer.boot.controller
 * @author youshipeng
 * @created 2017/5/4 15:25
 * <p>
 * Copyright 2016 ziroom
 */
package top.swimmer.boot.controller;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.UUIDEditor;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.MediaType;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import top.swimmer.boot.annotation.ApplicationController;
import top.swimmer.boot.dao.elasticsearch.KnowledgeInformationMapper;
import top.swimmer.boot.model.elasticsearch.KnowledgeInformation;
import top.swimmer.boot.model.elasticsearch.Tokenizer;
import top.swimmer.boot.model.options.PinyinWordSearchOptions;
import top.swimmer.boot.model.value.WordClickCount;
import top.swimmer.boot.service.PinyinWordService;
import top.swimmer.boot.util.ResponseUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.*;

import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
import static top.swimmer.tools.collection.CollectionUtils.isEmpty;

/**
 * <p></p>
 *
 * <PRE>
 * <BR>	修改记录
 * <BR>-----------------------------------------------
 * <BR>	修改日期			修改人			修改内容
 * </PRE>
 *
 * @author youshipeng
 * @since 1.0
 * @version 1.0
 */
@ApplicationController
@RequestMapping("/demo")
public class DemoController extends BaseController {

    @Resource(name = "knowledgeInformationMapper")
    KnowledgeInformationMapper knowledgeInformationMapper;

    @Resource(name = "pinyinWordService")
    private PinyinWordService pinyinWordService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String searchPage(HttpServletResponse response) throws Exception {
        KnowledgeInformation information = new KnowledgeInformation();
        information.setId("1111111111");
        information.setPushContent("我们都有一个家");
        knowledgeInformationMapper.insert(information);

        information.setId("222222");
        information.setPushContent("哥几个都有一个家");
        knowledgeInformationMapper.insert(information);

        information.setId("333333");
        information.setPushContent("咱们都有一个家");
        knowledgeInformationMapper.insert(information);

        information.setId("44444");
        information.setPushContent("朋友们都有一个家");
        knowledgeInformationMapper.insert(information);
        return "search";
    }

    @RequestMapping(value = "/find", method = RequestMethod.POST)
    public void find(HttpServletResponse response, @RequestBody Map<String, String> map) throws Exception {
        String input = map.get("input");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder searchQueryBuilder = boolQuery();
        List<String> words = knowledgeInformationMapper.analyze(input, Tokenizer.HAN_SEARCH);

        words.forEach(word -> {
            searchQueryBuilder.should(
                    multiMatchQuery(word, "pushContent^10", "pushContent.synonym")
                            .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)
                            .operator(MatchQueryBuilder.Operator.OR).tieBreaker(0.3f));
        });

        searchSourceBuilder.query(searchQueryBuilder);
        searchSourceBuilder.from(0).size(15).sort("_score", SortOrder.DESC);
        final List<KnowledgeInformation> knowledgeInformation = knowledgeInformationMapper.search(searchSourceBuilder);
        ResponseUtils.writeSuccessResponse(response, new ArrayList<String>(){{
            for (KnowledgeInformation entity : knowledgeInformation) {
                add(entity.getPushContent());
            }
        }});
    }

    @RequestMapping(value = "/synonyms", produces = MediaType.TEXT_PLAIN_VALUE, method = {RequestMethod.GET, RequestMethod.HEAD})
    public void synonymous(HttpServletResponse response) throws Exception {
        StringBuilder sb = new StringBuilder("");
        sb.append("我们 咱们 哥几个 朋友们\n");
        sb.append("起跑 开战 开讲 开课 开犁 开锄 开镰 开张 开盘 开拍\n");
        sb.append("停止 终止 休止 止息 停息 停歇 打住 止住 煞住 下马 平息 停 止 艾 寝 息 住 辍 歇 休 已 罢 适可而止 偃旗息鼓 鸣金收兵 停下 悬停 人亡政 停停 告一段落\n");
        sb.append("重复 反复 重 复 再 一再 再三 故伎重演 故态复萌 老生常谈 老调重弹 三翻四复 翻来覆去 颠来倒去 叠床架屋 重申 反反复复 故技重演 重蹈覆辙 重蹈 陈年老辞 重温 再行\n");
        sb.append("变化 变 转变 变动 更动 浮动 变通 变更 变卦 变迁 扭转 转移 转 弯 别 生成 变化无常 变型 思新求变 应时而变 走形 成形\n");
        response.setContentType("text/plain;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.addHeader("Last-Modified", UUID.randomUUID().toString());
        response.addHeader("ETag", UUID.randomUUID().toString());
        PrintWriter out = response.getWriter();
        out.write(sb.toString());
    }

    @RequestMapping(value = "/analyze", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
    public void search(HttpServletResponse response, @RequestBody Map<String, String> map) throws Exception {
        String input = map.get("input");
        List<List<WordClickCount>> results = pinyinWordService.analyzeSearch(input);
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        Set<String> content = new HashSet<>();
        Set<String> must = new HashSet<>();
        StringBuilder sb = new StringBuilder("");
        Double matchCount = 0.0;
        for (List<WordClickCount> son : results) {
            if (!isEmpty(son) && son.size() == 1) {
//                must.add(son.get(0).getWord());
                boolQueryBuilder.must(termQuery("pushContent", son.get(0).getWord()));
                continue;
            }
            matchCount += 1.0;
            for (WordClickCount clickCount : son) {
                sb.append(clickCount.getWord());
                content.add(clickCount.getWord());
            }
        }

        Double total = Double.valueOf(content.size());

        int minimumMatch = matchCount.equals(total) ? 99 : (int) (matchCount / total * 100) + 1;
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        boolQueryBuilder.must(termQuery("cityCode", "110000"));
//        if (!isCollectionEmpty(must)) {
//            boolQueryBuilder.must(termsQuery("pushContent", must));
//        }

        searchSourceBuilder.query(boolQueryBuilder);
        if (total != 0) {
            searchSourceBuilder.postFilter(multiMatchQuery(sb.toString(), "pushContent").minimumShouldMatch(minimumMatch + "%"));
        }
        searchSourceBuilder.highlight(
                new HighlightBuilder().field("pushContent").preTags("@preTag@").postTags("@postTag@")
        );
        searchSourceBuilder.from(0).size(15).sort("_score", SortOrder.DESC).sort("clicks", SortOrder.DESC);

        final List<KnowledgeInformation> knowledgeInformation = knowledgeInformationMapper.search(searchSourceBuilder);
        ResponseUtils.writeSuccessResponse(response, new ArrayList<String>(){{
            for (KnowledgeInformation entity : knowledgeInformation) {
                add(entity.getPushContent());
            }
        }});
    }
}